package top.rish.converter.core.utils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class RefKit {
    private static final Map<Class<?> ,Set<Field>> CACHE_FIELDS = new ConcurrentHashMap<>();

    public static <T>  T  getGenericClass(Class<?> c,int i){
        Type[] superclass = c.getGenericInterfaces();
        for (Type type : superclass) {
            if(type instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Type[] arguments = parameterizedType.getActualTypeArguments();
                if(i<arguments.length){
                    return (T) arguments[i];
                }
            }
        }
        return null;
    }

    public static Enum<?> getEnumByValue(Class<? extends Enum<?>> enumClass, Object value) {
        if (value instanceof CharSequence) {
            value = value.toString().trim();
        }

        final Set<Field> fields = getAllFields(enumClass);
        final Enum<?>[] enums = enumClass.getEnumConstants();
        String fieldName;
        for (Field field : fields) {
            fieldName = field.getName();
            if (field.getType().isEnum() ||
                    "ENUM$VALUES".equals(fieldName)
                    || "ordinal".equals(fieldName)) {
                // 跳过一些特殊字段
                continue;
            }
            for (Enum<?> enumObj : enums) {
                if (ObjKit.equal(value, getFieldValue(enumObj, field))) {
                    return  enumObj;
                }
            }
        }
        return null;
    }

    public static Set<Field> getAllFields(Object o){
        if(ObjKit.isEmpty(o)
                || ObjKit.isTypeCollect(o)
                || ObjKit.isMap(o)
                || ObjKit.isAnnotation(o)
                || ObjKit.isEnum(o)
                || ObjKit.isNumber(o)
        ){
            return ObjKit.newEpmtySet(Field.class);
        }
        Class<?> oc;
        if(o instanceof Class<?>){
            oc = (Class<?>) o;
        }else{
            oc = o.getClass();
        }
        if(ObjKit.isNotEmpty(CACHE_FIELDS.get(oc))){
            return CACHE_FIELDS.get(oc);
        }
        Field[] fields = oc.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
        }
        Set<Field> list = ObjKit.toSet(fields);
        CACHE_FIELDS.put(oc,list);
        return CACHE_FIELDS.get(oc);
    }

    public static Object getFieldValue(Object o, Field f) {
        if(!ObjKit.isAllNotEmpty(o,f)){
            return null;
        }
        try {
            f.setAccessible(true);
            return f.get(o);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
